package com.emovimento.synchronize;

import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.StandardCopyOption;
import java.nio.file.WatchEvent;
import java.util.logging.Logger;

/**
 * Synchronizes two directories in both directions.
 */
public class BothDirectionsSynchronizingDirectoryWatcher extends DirectoryWatcher {
  private static Logger LOGGER = Logger.getLogger("Synchronization");

  private final Path sourceDirectory;
  private final Path destinationDirectory;

  public BothDirectionsSynchronizingDirectoryWatcher(final Path sourceDirectory, final Path destinationDirectory) throws IOException {
    super(sourceDirectory, destinationDirectory);
    this.sourceDirectory = sourceDirectory;
    this.destinationDirectory = destinationDirectory;
  }

  @Override
  protected void entryCreated(WatchEvent<?> pathWatchEvent, final Path directory, final Path createdPath) throws IOException {
    entryChanged(directory, createdPath);
  }

  @Override
  protected void entryModified(WatchEvent<?> pathWatchEvent, final Path directory, final Path modifiedPath) throws IOException {
    entryChanged(directory, modifiedPath);
  }

  private void entryChanged(final Path directory, final Path changedPath) throws IOException {
    Path target = getDestination(directory, changedPath);
    boolean wasRegistered = unregister(target.getParent());
    LOGGER.info("Copying " + changedPath + " to " + target);
    Files.copy(changedPath, target, StandardCopyOption.COPY_ATTRIBUTES, StandardCopyOption.REPLACE_EXISTING);
    if (wasRegistered) register(target.getParent());
  }

  private Path getDestination(final Path directory, final Path changedPath) {
    Path destination;

    if (directory.startsWith(sourceDirectory)) {
      destination = destinationDirectory.resolve(changedPath.getFileName());
    } else {
      assert directory.startsWith(destinationDirectory);
      destination = sourceDirectory.resolve(changedPath.getFileName());
    }
    return destination;
  }

  @Override
  protected void entryDeleted(WatchEvent<?> pathWatchEvent, final Path directory, final Path deletedPath) throws IOException {
    Path target = getDestination(directory, deletedPath);
    boolean wasRegistered = unregister(target.getParent());
    LOGGER.info("Deleting " + deletedPath + " from " + target);
    Files.delete(getDestination(directory, deletedPath));
    if (wasRegistered) register(target.getParent());
  }
}
